//	--------------------------------------------------------------------
//	Copyright(C) 2006,2007 Zhao Yukun. All rights reserved.
//	This file is a part of the Xeres system.
//	Xeres 2007
//	Contact : xeres.engine@gmail.com
//	$(reservedInfo)
//	$(reservedDeclaration)
//	--------------------------------------------------------------------
///	@file	<CSprite10.cpp>
///	@path	~/src/graphics/dx10/
///	@date	2008/12/20
///	@desc	.

#include "config/config.h"

#include "lib/math/matrix.h"
#include "lib/math/math_win32.h"
#include "lib/system/thread_debug.h"

#include "graphics/DxHelpers.h"
#include "graphics/RenderContext.h"
#include "graphics/dx10/CSprite10.h"
#include "graphics/dx10/CFont10.h"
#include "graphics/dx10/import_dx10.h"

namespace xeres {

	IMPL_IOBJECT_CLASS( CSprite10 );

	// ctor
	CSprite10::CSprite10( ID3DX10Sprite * sprite )
		: m_pSprite( sprite )
		, m_backbufferSize( 0 , 0 )
	{
	}

	// dtor
	CSprite10::~CSprite10( void )
	{
		if( m_pSprite )
		{
			UINT rest = m_pSprite->Release();
			if( rest != 0 )
			{
				TRACE_ERROR( _S("CSprite10::DTOR: Invalid ID3DXSprite reference count.") );
				FATAL_ABORT( _S("Invalid ID3DXSprite reference count.") );
			}
		}
	}

	// on lost device
	bool CSprite10::OnLostDevice( void )
	{
		return true;
	}

	// on reset device
	bool CSprite10::OnResetDevice( RefWeak<IDevice> device )
	{
		m_backbufferSize = device->GetBackBufferSize();
		return true;
	}

	// draw text
	int CSprite10::DrawText( RefWeak<IFont> font , const WString& text ,
		int rect[4] , int style , PackColor4 color )
	{
		RefWeak<CFont10> font10 = font;
		return font10->DrawTextX( m_pSprite , text , rect , style , color.get_packed_argb() );
	}

	void CSprite10::Begin( RenderContext& rc )
	{
		m_pSprite->Begin( D3DX10_SPRITE_SORT_DEPTH_BACK_TO_FRONT );
		Matrix<float> mat;
		mat.identity();
		m_pSprite->SetViewTransform( (D3DXMATRIX*)&mat );
		m_backbufferSize.x = rc.ResX<int>();
		m_backbufferSize.y = rc.ResY<int>();
	}

	void CSprite10::End( RenderContext& rc )
	{
		m_pSprite->Flush();
		m_pSprite->End();
	}
	// DrawTexture
	void CSprite10::DrawTexture( RefWeak<ITexture> tex , const Rect<int> * rect , float depth )
	{
		ID3D10ShaderResourceView * view = NULL;
		tex->GetTextureInterface()->QueryInterface( IID_ID3D10ShaderResourceView , (void**)&view );
		if( view == NULL )
		{
			TRACE_ERROR( _S("CSprite10::DrawTexture: Invalid texture class %s to draw.") , tex->GetClassName().c_str() );
			return;
		}

		Pair<int> size = tex->GetSize();
		int width = size.x;
		int height = size.y;

		// make destination rectangle
		RECT rc;
		RECT rt = { 0 , 0 , width , height };
		if( rect )
		{
			rc.left = rect->left();
			rc.top = rect->top();
			rc.right = rect->right();
			rc.bottom = rect->bottom();
		}
		else
		{
			rc.left = rc.top = 0;
			rc.right = width;
			rc.bottom = height;
		}

		::OffsetRect( &rc, RectWidth( rc ) / 2, RectHeight( rc ) / 2 );

		float bb_w = float( m_backbufferSize.x );
		float bb_h = float( m_backbufferSize.y );

		float scale_x = (float)RectWidth( rc );
		float scale_y = (float)RectHeight( rc );

		D3DXVECTOR3 pos( (float)rc.left, (float)rc.top, depth );

		// make transform
		D3DXMATRIXA16 matScaling;
		D3DXMATRIXA16 matTranslation;
		dx10::D3DXMatrixScaling( &matScaling, scale_x, scale_y, 1.0f );
		dx10::D3DXMatrixTranslation( &matTranslation, pos.x, bb_h - pos.y, pos.z );

		D3DXMATRIXA16 matProjection;
		dx10::D3DXMatrixOrthoOffCenterLH( &matProjection, 0.0f, bb_w, 0.0f, bb_h, 0.1f, 10 );
		m_pSprite->SetProjectionTransform( &matProjection );

		D3DX10_SPRITE Sprite;

		dx10::D3DXMatrixMultiply( &Sprite.matWorld , &matScaling , &matTranslation );
		Sprite.pTexture = view;
		float fTexWidth = (float)width;
		float fTexHeight = (float)height;
		Sprite.TexCoord.x = (float)( rt.left ) / fTexWidth;
		Sprite.TexCoord.y = (float)( rt.top ) / fTexHeight;
		Sprite.TexSize.x = (float)( rt.right - rt.left ) / fTexWidth;
		Sprite.TexSize.y = (float)( rt.bottom - rt.top ) / fTexHeight;
		Sprite.TextureIndex = 0;
		Sprite.ColorModulate = D3DXCOLOR(1,1,1,1);

		HRESULT hr = m_pSprite->DrawSpritesImmediate( &Sprite , 1 , 0 , 0 );
		view->Release();
		if( FAILED(hr) )
		{
			TRACE_ERROR( _S("CSprite10::DrawTexture: Failed to draw texture: %s") ,
				d3d_get_err(hr) );
		}
	}

} // namespace xeres
